/*
 * hetao - High Performance Web Server
 * author	: calvin
 * email	: calvinwilliams@163.com
 *
 * Licensed under the LGPL v2.1, see the file LICENSE in base directory.
 */

#include "hetao_in.h"
#include "hetao_rest.h"

static int _ParseUriPathsMatch( struct RestServiceRoute *p_route , char *uri_paths_match )
{
	char		*p1 = NULL ;
	char		*p2 = NULL ;
	
	if( uri_paths_match[0] != '/' )
		return REST_ERROR_URI_FIRST_CHARACTER_IN_CONFIG;
	
	p_route->http_uri_paths_count = 0 ;
	p2 = p1 = uri_paths_match + 1 ;
	while(1)
	{
		if( (*p2) == '\0' )
		{
			if( p_route->http_uri_paths_count >= sizeof(p_route->http_uri_paths)/sizeof(p_route->http_uri_paths[0]) )
				return REST_ERROR_TOO_MANY_HTTP_URI_PATHS_IN_CONFIG;
			p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path = p1 ;
			p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path_len = p2 - p1 ;
			DebugLog( __FILE__ , __LINE__ , "parse out config path[%.*s]" , p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path_len,p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path );
			p_route->http_uri_paths_count++;
			
			return 0;
		}
		else if( (*p2) == '/' )
		{
			if( p_route->http_uri_paths_count >= sizeof(p_route->http_uri_paths)/sizeof(p_route->http_uri_paths[0]) )
				return -1;
			p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path = p1 ;
			p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path_len = p2 - p1 ;
			DebugLog( __FILE__ , __LINE__ , "parse out config path[%.*s]" , p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path_len,p_route->http_uri_paths[p_route->http_uri_paths_count].http_uri_path );
			p_route->http_uri_paths_count++;
			
			p2 = p1 = p2 + 1 ;
		}
		else
		{
			p2++;
		}
	}
}

struct RestServiceControler *RESTCreateRestServiceControler( struct RestServiceConfig *config_array )
{
	struct RestServiceControler	*p_controler = NULL ;
	struct RestServiceConfig	*p_config = NULL ;
	struct RestServiceRoute		*p_route = NULL ;
	
	int				nret = 0 ;
	
	DebugLog( __FILE__ , __LINE__ , "enter RESTCreateRestServiceControler" );
	
	p_controler = (struct RestServiceControler *)malloc( sizeof(struct RestServiceControler) ) ; 
	if( p_controler == NULL )
		return NULL;
	memset( p_controler , 0x00 , sizeof(struct RestServiceControler) );
	
	INIT_LIST_HEAD( & (p_controler->routes_list) );
	
	for( p_config = config_array ; p_config->http_method[0] ; p_config++ )
	{
		p_route = (struct RestServiceRoute *)malloc( sizeof(struct RestServiceRoute) ) ;
		if( p_route == NULL )
		{
			RESTDestroyRestServiceControler( p_controler );
			return NULL;
		}
		
		p_route->http_method_len = strlen(p_config->http_method) ;
		if( p_route->http_method_len > sizeof(p_route->http_method)-1 )
			p_route->http_method_len = sizeof(p_route->http_method)-1 ;
		strncpy( p_route->http_method , p_config->http_method , p_route->http_method_len );
		
		nret = _ParseUriPathsMatch( p_route , p_config->http_uri_paths_match ) ;
		if( nret )
		{
			ErrorLog( __FILE__ , __LINE__ , "_ParseUriPathsMatch failed[%d] , uri_paths_match[%s]" , nret , p_config->http_uri_paths_match );
			RESTDestroyRestServiceControler( p_controler );
			return NULL;
		}
		
		p_route->pfuncRestServiceEntry = p_config->pfuncRestServiceEntry ;
		
		list_add_tail( & (p_route->route_list_node) , & (p_controler->routes_list) );
		InfoLog( __FILE__ , __LINE__ , "add a route[%.*s][%d][%.*s%s][%p] to rest service control" , p_route->http_method_len,p_route->http_method , p_route->http_uri_paths_count , (p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path_len:0),(p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path:"") , (p_route->http_uri_paths_count>0?",...":"") , p_route->pfuncRestServiceEntry );
	}
	
	DebugLog( __FILE__ , __LINE__ , "leave RESTCreateRestServiceControler" );
	
	return p_controler;
}

int RESTDispatchRestServiceControler( struct RestServiceControler *ctl , struct HttpApplicationContext *hp_ctx )
{
	struct RestServiceContext	ctx ;
	
	struct RestServiceRoute		*p_route = NULL ;
	
	int				uri_path_index ;
	
	int				nret = 0 ;
	
	DebugLog( __FILE__ , __LINE__ , "enter RESTDispatchRestServiceControler" );
	
	nret = ParseHttpUriToRestServiceContext( hp_ctx , & ctx ) ;
	if( nret )
	{
		ErrorLog( __FILE__ , __LINE__ , "ParseHttpUriToRestServiceContext failed[%d]" , nret );
		return nret;
	}
	else
	{
		DebugLog( __FILE__ , __LINE__ , "ParseHttpUriToRestServiceContext ok" );
	}
	
	list_for_each_entry( p_route , & (ctl->routes_list) , struct RestServiceRoute , route_list_node )
	{
		DebugLog( __FILE__ , __LINE__ , "travel a route[%.*s][%d][%.*s%s][%p] in rest service controler" , p_route->http_method_len,p_route->http_method , p_route->http_uri_paths_count , (p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path_len:0),(p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path:"") , (p_route->http_uri_paths_count>0?",...":"") , p_route->pfuncRestServiceEntry );
		
		DebugLog( __FILE__ , __LINE__ , "diff config_method[%.*s] and http_method[%.*s] , diff config_paths_count[%d] and http_paths_count[%d]" , p_route->http_method_len,p_route->http_method , ctx.http_method_len,ctx.http_method , p_route->http_uri_paths_count , ctx.http_uri_paths_count );
		if( STRNCMPSTRN( p_route->http_method , p_route->http_method_len , == , ctx.http_method , ctx.http_method_len ) && p_route->http_uri_paths_count == ctx.http_uri_paths_count )
		{
			uri_path_index = 0 ;
			while( uri_path_index < p_route->http_uri_paths_count )
			{
				DebugLog( __FILE__ , __LINE__ , "uri_path_index[%d] : diff config_path[%.*s] and http_path[%.*s]" , uri_path_index , p_route->http_uri_paths[uri_path_index].http_uri_path_len,p_route->http_uri_paths[uri_path_index].http_uri_path , ctx.http_uri_paths[uri_path_index].path_len,ctx.http_uri_paths[uri_path_index].path );
				if( STRNEQRSTR( p_route->http_uri_paths[uri_path_index].http_uri_path , p_route->http_uri_paths[uri_path_index].http_uri_path_len , "{}" ) )
					;
				else if( STRNCMPSTRN( p_route->http_uri_paths[uri_path_index].http_uri_path , p_route->http_uri_paths[uri_path_index].http_uri_path_len , == , ctx.http_uri_paths[uri_path_index].path , ctx.http_uri_paths[uri_path_index].path_len ) )
					;
				else
					break;
				uri_path_index++;
			}
			if( uri_path_index == p_route->http_uri_paths_count )
			{
				struct RestServiceRoute		*p_first_rut = list_first_entry( & (ctl->routes_list) , struct RestServiceRoute , route_list_node ) ;
				
				if( p_route != p_first_rut )
				{
					list_del( & (p_route->route_list_node) );
					LIST_ADD( & (p_route->route_list_node) , & (ctl->routes_list) );
				}
				
				DebugLog( __FILE__ , __LINE__ , "call RestService in route[%.*s][%d][%.*s%s][%p] in rest service control" , p_route->http_method_len,p_route->http_method , p_route->http_uri_paths_count , (p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path_len:0),(p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path:"") , (p_route->http_uri_paths_count>0?",...":"") , p_route->pfuncRestServiceEntry );
				nret = p_route->pfuncRestServiceEntry( & ctx ) ;
				if( nret < 0 )
				{
					FatalLog( __FILE__ , __LINE__ , "pfuncRestServiceEntry return [%d]" , nret );
				}
				else if( nret > 0 )
				{
					ErrorLog( __FILE__ , __LINE__ , "pfuncRestServiceEntry return [%d]" , nret );
				}
				else
				{
					DebugLog( __FILE__ , __LINE__ , "pfuncRestServiceEntry return [%d]" , nret );
				}
				
				return nret;
			}
		}
	}
	
	DebugLog( __FILE__ , __LINE__ , "leave RESTDispatchRestServiceControler" );
	
	return REST_ERROR_NO_SERVICE_IN_CONFIG;
}

void RESTDestroyRestServiceControler( struct RestServiceControler *ctl )
{
	struct RestServiceRoute	*p_route = NULL ;
	struct RestServiceRoute	*p_next_rut = NULL ;
	
	DebugLog( __FILE__ , __LINE__ , "enter RSAPIDestroyRestServiceControler" );
	
	list_for_each_entry_safe( p_route , p_next_rut , & (ctl->routes_list) , struct RestServiceRoute , route_list_node )
	{
		InfoLog( __FILE__ , __LINE__ , "delete a route[%.*s][%d][%.*s%s][%p] from rest service control" , p_route->http_method_len,p_route->http_method , p_route->http_uri_paths_count , (p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path_len:0),(p_route->http_uri_paths_count>0?p_route->http_uri_paths[0].http_uri_path:"") , (p_route->http_uri_paths_count>0?",...":"") , p_route->pfuncRestServiceEntry );
		list_del( & (p_route->route_list_node) );
		free( p_route );
	}
	
	free( ctl );
	
	DebugLog( __FILE__ , __LINE__ , "leave RESTDestroyRestServiceControler" );
	
	return;
}

